#include "iConfig.hpp"

#include <glf/input/inputManager.h>

namespace glf {
namespace input {

struct ImplBase {
	InputManager& mInputMgr;
	bool mIsAccelerometerEnabled;
	bool mIsGyroEnabled;

	ImplBase(InputManager& inputMgr) 
		:	mInputMgr(inputMgr)
		,	mIsAccelerometerEnabled(false)
		,	mIsGyroEnabled(false)
	{
	}
	virtual ~ImplBase() {
	}
	virtual void EnableAccelerometer(bool isEnabled, float frequency) {
	}
	virtual bool EnableGyro(bool isEnabled, float frequency) {
		return false;
	}
	virtual void EnableSensor(bool isEnabled) {
	}
	virtual void UpdateFrame() {
	}
	virtual void PreUpdateFrame() {
	}
	virtual bool OnEvent(const CoreEvent& evt) {
		return false;
	}
	virtual void StartDuoProtocol(bool isThreaded) {
	}
};

}
}

#if GLF_PLATFORM_IPHONE
	#include "inputManager_iphone_.hpp"
#elif GLF_PLATFORM_MACOSX
	#include "inputManager_macosx_.hpp"
#else
	#include GLFi_HEADER_API(inputManager, GLF_API_INPUT)
#endif


namespace glf {

InputManager::InputManager() 
	:	m(GLF_NEW_IMPL(*this)) 
{
	GLF_CHECK_IMPL_SIZE();
} 

InputManager::~InputManager() {
	GLF_DELETE_IMPL();
}

void InputManager::UpdateFrame() {
	m.PreUpdateFrame();

	{
		LockGuard<Mutex> lock(mMutex);
		//reset input device states
		for (std::set<InputDevice *>::const_iterator
			it = mUpdatedDevices.begin(), end = mUpdatedDevices.end(); it != end; ++it)
			(*it)->ResetFrame();
		mUpdatedDevices.clear();
	}
	//implementation specific update
	m.UpdateFrame();
}

Keyboard& InputManager::GetKeyboard(uint idx) {
	return m.GetKeyboard(idx);
}

Mouse& InputManager::GetMouse(uint idx) {
	return m.GetMouse(idx);
}

Gamepad& InputManager::GetGamepad(uint idx) {
	return m.GetGamepad(idx);
}

size_t InputManager::GetKeyboardCount() const
{
	return m.GetKeyboardCount();
}
		
size_t InputManager::GetMouseCount() const
{
	return m.GetMouseCount();
}
		
size_t InputManager::GetGamepadCount() const
{
	return m.GetGamepadCount();
}

size_t InputManager::GetKeyboardIndex(const InputDevice *inputDevice)
{
	GLF_ASSERT(inputDevice->GetInputManager() == this);
	for (size_t i = 0, count = GetKeyboardCount(); i < count; ++i)
		if (&GetKeyboard(i) == inputDevice)
			return i;
	return 0;
}

size_t InputManager::GetMouseIndex(const InputDevice *inputDevice)
{
	GLF_ASSERT(inputDevice->GetInputManager() == this);
	for (size_t i = 0, count = GetMouseCount(); i < count; ++i)
		if (&GetMouse(i) == inputDevice)
			return i;
	return 0;
}

size_t InputManager::GetGamepadIndex(const InputDevice *inputDevice)
{
	GLF_ASSERT(inputDevice->GetInputManager() == this);
	for (size_t i = 0, count = GetGamepadCount(); i < count; ++i)
		if (&GetGamepad(i) == inputDevice)
			return i;
	return 0;
}

void InputManager::EnableAccelerometer(bool isEnabled, float frequency) {
	m.EnableAccelerometer(isEnabled, frequency);
}

bool InputManager::EnableGyro(bool isEnabled, float frequency) {
	return m.EnableGyro(isEnabled, frequency);
}

bool InputManager::IsAccelerometerEnabled() const {
	return m.mIsAccelerometerEnabled;
}

void InputManager::EnableSensor(bool isEnabled) {
	m.EnableSensor(isEnabled);
}

void InputManager::EmulateGamepadWin32(GamepadType type) {
#if defined(GLF_PLATFORM_WIN32) || defined(GLF_PLATFORM_MACOSX)
	m.EmulateGamepad(type);
#endif
}

void InputManager::AddUpdatedDevice(InputDevice *device) 
{
	GLF_ASSERT(device->GetInputManager() == this);
	LockGuard<Mutex> lock(mMutex);
	mUpdatedDevices.insert(device);
}

bool InputManager::OnEvent(const CoreEvent& evt) {
	return m.OnEvent(evt);
}

void InputManager::StartDuoProtocol(bool isThreaded) {
	m.StartDuoProtocol(isThreaded);
}

} //namespace glf

